<?php
/**
 * 核心功能函数库
 * 
 * 这个文件包含了博客系统的核心功能函数
 * 使用简单的mysqli直连方式，严格按照main.sql的表结构
 * 这些函数提供了用户管理、文章管理、评论管理等基础功能
 * 
 * 设计原则：
 * - 使用mysqli直连数据库，避免PDO的复杂性
 * - 严格按照数据库表结构设计函数
 * - 每个函数都有详细的中文注释
 * - 函数命名清晰明确，便于理解和维护
 * 
 * 主要功能模块：
 * - 用户认证：登录、注册、会话管理
 * - 文章管理：发布、编辑、删除、查询
 * - 评论管理：发布、删除评论
 * - 数据统计：获取各种统计数据
 * - 工具函数：重定向、转义、格式化等
 * 
 * 注意事项：
 * - 所有函数都假设$conn全局变量已经初始化
 * - 使用session_start()进行会话管理
 * - 所有用户输入都应该进行适当的转义处理
 */

// 启动会话管理
// 确保在任何输出之前启动会话
session_start();

/**
 * 用户登录验证函数
 * 
 * 这个函数处理用户登录逻辑，验证用户名和密码
 * 登录成功后会在session中保存用户信息
 * 
 * @param string $username 用户输入的用户名
 * @param string $password 用户输入的原始密码（未加密）
 * @return bool 登录是否成功，true表示成功，false表示失败
 * 
 * 处理流程：
 * 1. 根据用户名查询数据库中的用户记录
 * 2. 使用password_verify()验证密码是否正确
 * 3. 验证成功后在session中保存用户ID和用户名
 * 4. 返回登录结果
 * 
 * 使用示例：
 * if (loginUser('admin', '123456')) {
 *     echo '登录成功';
 *     header('Location: index.php');
 * } else {
 *     echo '用户名或密码错误';
 * }
 */
function loginUser($username, $password) {
    global $conn;
    
    // 查询用户信息，根据用户名获取用户记录
    // 注意：这里直接使用字符串拼接，生产环境建议使用预处理语句
    $sql = "SELECT `id`, `用户名`, `密码` FROM `用户表` WHERE `用户名` = '$username'";
    $result = mysqli_query($conn, $sql);
    
    // 检查查询是否成功且找到了用户记录
    if ($result && mysqli_num_rows($result) > 0) {
        // 获取用户数据
        $user = mysqli_fetch_assoc($result);
        
        // 使用password_verify验证密码
        // $user['密码']是数据库中存储的哈希密码
        // $password是用户输入的原始密码
        if (password_verify($password, $user['密码'])) {
            // 密码验证成功，设置会话信息
            $_SESSION['user_id'] = $user['id'];
            $_SESSION['username'] = $user['用户名'];
            return true;
        }
    }
    
    // 用户不存在或密码错误，返回false
    return false;
}

/**
 * 用户注册函数
 * 
 * 这个函数处理新用户注册逻辑
 * 会检查用户名是否已存在，然后创建新用户账户
 * 
 * @param string $username 要注册的用户名
 * @param string $password 用户设置的密码（原始密码）
 * @return bool 注册是否成功，true表示成功，false表示失败（通常是用户名已存在）
 * 
 * 处理流程：
 * 1. 检查用户名是否已经被占用
 * 2. 使用password_hash()加密用户密码
 * 3. 将新用户信息插入数据库
 * 4. 返回注册结果
 * 
 * 使用示例：
 * if (registerUser('newuser', 'password123')) {
 *     echo '注册成功，请登录';
 * } else {
 *     echo '注册失败，用户名可能已存在';
 * }
 */
function registerUser($username, $password) {
    global $conn;
    
    // 首先检查用户名是否已经存在
    // 避免重复注册相同用户名
    $sql = "SELECT `id` FROM `用户表` WHERE `用户名` = '$username'";
    $result = mysqli_query($conn, $sql);
    
    // 如果查询到记录，说明用户名已存在
    if ($result && mysqli_num_rows($result) > 0) {
        return false; // 用户名已存在，注册失败
    }
    
    // 使用password_hash()加密密码
    // PASSWORD_DEFAULT会使用当前PHP版本推荐的加密算法
    $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
    
    // 插入新用户记录到数据库
    $sql = "INSERT INTO `用户表` (`用户名`, `密码`) VALUES ('$username', '$hashedPassword')";
    return mysqli_query($conn, $sql);
}

/**
 * 检查用户是否已登录
 * 
 * 这个函数检查当前用户的登录状态
 * 通过检查session中是否存在有效的用户ID来判断
 * 
 * @return bool 用户是否已登录，true表示已登录，false表示未登录
 * 
 * 使用示例：
 * if (isLoggedIn()) {
 *     echo '欢迎回来，' . $_SESSION['username'];
 * } else {
 *     echo '请先登录';
 * }
 */
function isLoggedIn() {
    // 检查session中是否存在user_id且不为空
    return isset($_SESSION['user_id']) && !empty($_SESSION['user_id']);
}

/**
 * 获取当前登录用户的完整信息
 * 
 * 这个函数返回当前登录用户的详细信息
 * 如果用户未登录，则返回null
 * 
 * @return array|null 用户信息数组或null（未登录时）
 *                   用户信息包含：id, 用户名, 密码, 创建时间等字段
 * 
 * 使用示例：
 * $user = getCurrentUser();
 * if ($user) {
 *     echo '当前用户：' . $user['用户名'];
 *     echo '注册时间：' . $user['创建时间'];
 * }
 */
function getCurrentUser() {
    // 如果用户未登录，直接返回null
    if (!isLoggedIn()) {
        return null;
    }
    
    global $conn;
    // 从session中获取用户ID
    $userId = $_SESSION['user_id'];
    
    // 根据用户ID查询完整的用户信息
    $sql = "SELECT * FROM `用户表` WHERE `id` = $userId";
    $result = mysqli_query($conn, $sql);
    
    // 如果查询成功且找到记录，返回用户信息
    if ($result && mysqli_num_rows($result) > 0) {
        return mysqli_fetch_assoc($result);
    }
    
    // 查询失败或用户不存在，返回null
    return null;
}

/**
 * 用户退出登录函数
 * 
 * 这个函数处理用户登出逻辑
 * 会清除所有session数据并销毁会话
 * 
 * 使用示例：
 * logoutUser();
 * header('Location: login.php');
 */
function logoutUser() {
    // 销毁当前会话
    session_destroy();
    // 清空session数组
    $_SESSION = array();
}

/**
 * 获取文章列表（分页）
 * 
 * 这个函数获取文章列表，支持分页功能
 * 文章按置顶状态和发布时间排序（置顶文章优先显示）
 * 
 * @param int $page 页码，从1开始
 * @param int $limit 每页显示的文章数量，默认10篇
 * @return array 文章列表数组，每个元素包含文章的基本信息
 * 
 * 返回的文章信息包含：
 * - id: 文章ID
 * - 标题: 文章标题
 * - 内容: 文章内容
 * - 创建时间: 发布时间
 * - 阅读量、点赞量、评论量: 统计数据
 * - 是否置顶、是否推荐: 特殊标记
 * - 用户名: 作者用户名
 * 
 * 使用示例：
 * $articles = getArticleList(1, 5); // 获取第1页，每页5篇文章
 * foreach ($articles as $article) {
 *     echo $article['标题'] . ' - ' . $article['用户名'];
 * }
 */
function getArticleList($page = 1, $limit = 10) {
    global $conn;
    
    // 计算偏移量，用于分页查询
    // 第1页偏移量为0，第2页偏移量为$limit，以此类推
    $offset = ($page - 1) * $limit;
    
    // 构建SQL查询语句
    // 使用LEFT JOIN连接文章表和用户表，获取作者信息
    // 按置顶状态降序、创建时间降序排列（置顶文章优先，新文章在前）
    $sql = "SELECT a.`id`, a.`标题`, a.`内容`, a.`创建时间`, a.`阅读量`, a.`点赞量`, a.`评论量`, a.`是否置顶`, a.`是否推荐`, u.`用户名`
            FROM `文章表` a 
            LEFT JOIN `用户表` u ON a.`用户ID` = u.`id`
            ORDER BY a.`是否置顶` DESC, a.`创建时间` DESC 
            LIMIT $offset, $limit";
    
    // 执行查询
    $result = mysqli_query($conn, $sql);
    $articles = array();
    
    // 如果查询成功，遍历结果集
    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $articles[] = $row;
        }
    }
    
    return $articles;
}

/**
 * 获取文章总数
 * 
 * 这个函数返回数据库中文章的总数量
 * 主要用于分页计算
 * 
 * @return int 文章总数
 * 
 * 使用示例：
 * $totalArticles = getArticleCount();
 * $totalPages = ceil($totalArticles / $articlesPerPage);
 */
function getArticleCount() {
    global $conn;
    
    // 查询文章总数
    $sql = "SELECT COUNT(*) as total FROM `文章表`";
    $result = mysqli_query($conn, $sql);
    
    // 如果查询成功，返回总数
    if ($result) {
        $row = mysqli_fetch_assoc($result);
        return $row['total'];
    }
    
    // 查询失败，返回0
    return 0;
}

/**
 * 根据ID获取单篇文章的详细信息
 * 
 * 这个函数根据文章ID获取文章的完整信息
 * 包含文章内容和作者信息
 * 
 * @param int $id 文章ID
 * @return array|null 文章信息数组或null（文章不存在时）
 * 
 * 返回的文章信息包含文章表的所有字段和作者用户名
 * 
 * 使用示例：
 * $article = getArticleById(1);
 * if ($article) {
 *     echo $article['标题'];
 *     echo $article['内容'];
 *     echo '作者：' . $article['用户名'];
 * } else {
 *     echo '文章不存在';
 * }
 */
function getArticleById($id) {
    global $conn;
    
    // 根据文章ID查询文章详情，同时获取作者信息
    $sql = "SELECT a.*, u.`用户名` 
            FROM `文章表` a 
            LEFT JOIN `用户表` u ON a.`用户ID` = u.`id`
            WHERE a.`id` = $id";
    
    $result = mysqli_query($conn, $sql);
    
    // 如果查询成功且找到记录，返回文章信息
    if ($result && mysqli_num_rows($result) > 0) {
        return mysqli_fetch_assoc($result);
    }
    
    // 文章不存在，返回null
    return null;
}

/**
 * 增加文章阅读量
 * 
 * 这个函数用于增加指定文章的阅读量
 * 通常在用户访问文章详情页时调用
 * 
 * @param int $id 文章ID
 * 
 * 使用示例：
 * increaseViewCount($articleId); // 文章阅读量+1
 */
function increaseViewCount($id) {
    global $conn;
    
    // 将指定文章的阅读量增加1
    $sql = "UPDATE `文章表` SET `阅读量` = `阅读量` + 1 WHERE `id` = $id";
    mysqli_query($conn, $sql);
}

/**
 * 发布新文章
 * 
 * 这个函数用于发布新文章到数据库
 * 支持设置置顶、推荐状态和文章配图
 * 
 * @param string $title 文章标题
 * @param string $content 文章内容
 * @param int $userId 作者用户ID
 * @param int $isTop 是否置顶（1为置顶，0为普通）
 * @param int $isRecommend 是否推荐（1为推荐，0为普通）
 * @param string $imagePath 文章配图路径（可选）
 * @return bool 发布是否成功
 * 
 * 使用示例：
 * $success = publishArticle(
 *     '我的第一篇文章',
 *     '这是文章内容...',
 *     $_SESSION['user_id'],
 *     0, // 不置顶
 *     1, // 推荐
 *     'uploads/images/article1.jpg'
 * );
 */
function publishArticle($title, $content, $userId, $isTop = 0, $isRecommend = 0, $imagePath = '') {
    global $conn;
    
    // 插入新文章记录
    // 创建时间会自动设置为当前时间（数据库默认值）
    $sql = "INSERT INTO `文章表` (`标题`, `内容`, `用户ID`, `是否置顶`, `是否推荐`, `图片`) 
            VALUES ('$title', '$content', $userId, $isTop, $isRecommend, '$imagePath')";
    
    return mysqli_query($conn, $sql);
}

/**
 * 获取指定文章的分类信息
 * 
 * 这个函数获取某篇文章所属的所有分类
 * 一篇文章可以属于多个分类
 * 
 * @param int $articleId 文章ID
 * @return array 分类列表数组，每个元素包含分类名称
 * 
 * 使用示例：
 * $categories = getArticleCategories(1);
 * foreach ($categories as $category) {
 *     echo $category['分类名'] . ' ';
 * }
 */
function getArticleCategories($articleId) {
    global $conn;
    
    // 通过文章分类关联表查询文章的分类信息
    // 使用LEFT JOIN连接分类表获取分类名称
    $sql = "SELECT c.`分类名` 
            FROM `文章分类表` ac 
            LEFT JOIN `分类表` c ON ac.`分类ID` = c.`id`
            WHERE ac.`文章ID` = $articleId";
    
    $result = mysqli_query($conn, $sql);
    $categories = array();
    
    // 如果查询成功，遍历结果集
    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $categories[] = $row['分类名'];
        }
    }
    
    return $categories;
}

/**
 * 获取指定文章的标签信息
 * 
 * 这个函数获取某篇文章关联的所有标签
 * 一篇文章可以有多个标签
 * 
 * @param int $articleId 文章ID
 * @return array 标签列表数组，每个元素包含标签名称
 * 
 * 使用示例：
 * $tags = getArticleTags(1);
 * foreach ($tags as $tag) {
 *     echo '#' . $tag . ' ';
 * }
 */
function getArticleTags($articleId) {
    global $conn;
    
    // 通过文章标签关联表查询文章的标签信息
    // 使用LEFT JOIN连接标签表获取标签名称
    $sql = "SELECT t.`标签名` 
            FROM `文章标签表` at 
            LEFT JOIN `标签表` t ON at.`标签ID` = t.`id`
            WHERE at.`文章ID` = $articleId";
    
    $result = mysqli_query($conn, $sql);
    $tags = array();
    
    // 如果查询成功，遍历结果集
    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $tags[] = $row['标签名'];
        }
    }
    
    return $tags;
}

/**
 * 获取指定文章的评论列表
 * 
 * 这个函数获取某篇文章的所有评论
 * 评论按时间降序排列（最新评论在前）
 * 
 * @param int $articleId 文章ID
 * @return array 评论列表数组，每个评论包含：
 *              - comment_id: 评论ID
 *              - 评论内容: 评论正文
 *              - 评论时间: 评论发布时间
 *              - 评论用户ID: 评论者ID
 *              - 用户名: 评论者用户名
 * 
 * 使用示例：
 * $comments = getArticleComments(1);
 * foreach ($comments as $comment) {
 *     echo $comment['用户名'] . ': ' . $comment['评论内容'];
 * }
 */
function getArticleComments($articleId) {
    global $conn;
    
    // 查询文章的评论信息，包含评论者信息
    // 通过多表JOIN获取完整的评论数据
    $sql = "SELECT c.`id` as comment_id, c.`评论内容`, c.`评论时间`, c.`评论用户ID`, u.`用户名`
            FROM `文章评论表` ac 
            LEFT JOIN `评论表` c ON ac.`评论ID` = c.`id`
            LEFT JOIN `用户表` u ON c.`评论用户ID` = u.`id`
            WHERE ac.`文章ID` = $articleId
            ORDER BY c.`评论时间` DESC";
    
    $result = mysqli_query($conn, $sql);
    $comments = array();
    
    // 如果查询成功，遍历结果集
    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $comments[] = $row;
        }
    }
    
    return $comments;
}

/**
 * 发布新评论
 * 
 * 这个函数用于发布新评论到指定文章
 * 需要先在评论表中插入评论，再建立文章评论关联
 * 
 * @param int $articleId 目标文章ID
 * @param int $userId 评论者用户ID
 * @param string $content 评论内容
 * @return bool 发布是否成功
 * 
 * 处理流程：
 * 1. 在评论表中插入新评论记录
 * 2. 获取新插入评论的ID
 * 3. 在文章评论关联表中建立关联关系
 * 4. 返回操作结果
 * 
 * 使用示例：
 * $success = publishComment(1, $_SESSION['user_id'], '这是一条评论');
 * if ($success) {
 *     echo '评论发布成功';
 * }
 */
function publishComment($articleId, $userId, $content) {
    global $conn;
    
    // 第一步：插入评论到评论表
    $sql1 = "INSERT INTO `评论表` (`评论内容`, `评论用户ID`) VALUES ('$content', $userId)";
    $result1 = mysqli_query($conn, $sql1);
    
    // 如果评论插入成功，继续建立关联
    if ($result1) {
        // 获取刚插入的评论ID
        $commentId = mysqli_insert_id($conn);
        
        // 第二步：建立文章评论关联关系
        $sql2 = "INSERT INTO `文章评论表` (`文章ID`, `评论ID`) VALUES ($articleId, $commentId)";
        return mysqli_query($conn, $sql2);
    }
    
    // 评论插入失败，返回false
    return false;
}

/**
 * 获取所有文章分类
 * 
 * 这个函数获取系统中的所有分类信息
 * 分类按排序字段排列
 * 
 * @return array 分类列表数组，每个分类包含完整的分类信息
 * 
 * 使用示例：
 * $categories = getAllCategories();
 * foreach ($categories as $category) {
 *     echo '<option value="' . $category['id'] . '">' . $category['分类名'] . '</option>';
 * }
 */
function getAllCategories() {
    global $conn;
    
    // 查询所有分类，按排序字段排列
    $sql = "SELECT * FROM `分类表` ORDER BY `分类排序`";
    $result = mysqli_query($conn, $sql);
    $categories = array();
    
    // 如果查询成功，遍历结果集
    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $categories[] = $row;
        }
    }
    
    return $categories;
}

/**
 * 获取所有文章标签
 * 
 * 这个函数获取系统中的所有标签信息
 * 标签按排序字段排列
 * 
 * @return array 标签列表数组，每个标签包含完整的标签信息
 * 
 * 使用示例：
 * $tags = getAllTags();
 * foreach ($tags as $tag) {
 *     echo '<span class="tag">' . $tag['标签名'] . '</span>';
 * }
 */
function getAllTags() {
    global $conn;
    
    // 查询所有标签，按排序字段排列
    $sql = "SELECT * FROM `标签表` ORDER BY `标签排序`";
    $result = mysqli_query($conn, $sql);
    $tags = array();
    
    // 如果查询成功，遍历结果集
    if ($result) {
        while ($row = mysqli_fetch_assoc($result)) {
            $tags[] = $row;
        }
    }
    
    return $tags;
}

/**
 * 页面重定向函数
 * 
 * 这个函数用于页面跳转，发送HTTP重定向头部
 * 调用后会立即终止脚本执行
 * 
 * @param string $url 要跳转的目标地址（相对或绝对URL）
 * 
 * 使用示例：
 * redirect('login.php'); // 跳转到登录页
 * redirect('http://www.example.com'); // 跳转到外部网站
 */
function redirect($url) {
    // 发送HTTP重定向头部
    header("Location: $url");
    // 立即终止脚本执行，防止后续代码运行
    exit();
}

/**
 * HTML字符转义函数
 * 
 * 这个函数用于防止XSS攻击，将特殊字符转换为HTML实体
 * 所有用户输入的内容在输出到页面前都应该使用此函数转义
 * 
 * @param string $string 要转义的原始字符串
 * @return string 转义后的安全字符串
 * 
 * 转义的字符包括：
 * - < 转为 &lt;
 * - > 转为 &gt;
 * - " 转为 &quot;
 * - ' 转为 &#039;
 * - & 转为 &amp;
 * 
 * 使用示例：
 * echo escape($userInput); // 安全输出用户输入
 * echo '<input value="' . escape($value) . '">'; // 安全的属性值
 */
function escape($string) {
    // 使用htmlspecialchars进行转义
    // ENT_QUOTES: 转义单引号和双引号
    // UTF-8: 指定字符编码
    return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}

/**
 * 日期时间格式化函数
 * 
 * 这个函数将数据库中的日期时间格式化为易读的格式
 * 
 * @param string $datetime 原始日期时间字符串
 * @return string 格式化后的日期时间字符串（Y-m-d H:i格式）
 * 
 * 使用示例：
 * echo formatDate('2025-01-06 14:30:25'); // 输出: 2025-01-06 14:30
 * echo formatDate($article['创建时间']); // 格式化文章创建时间
 */
function formatDate($datetime) {
    // 使用strtotime将字符串转为时间戳，再用date格式化
    return date('Y-m-d H:i', strtotime($datetime));
}

/**
 * 文章内容摘要截取函数
 * 
 * 这个函数从文章内容中截取指定长度的摘要
 * 如果内容长度超过限制，会在末尾添加省略号
 * 支持中文字符的正确截取
 * 
 * @param string $content 原始文章内容
 * @param int $length 摘要最大长度（字符数），默认200字符
 * @return string 截取后的摘要文本
 * 
 * 使用示例：
 * echo getExcerpt($article['内容'], 100); // 截取100字符摘要
 * echo getExcerpt($longText); // 使用默认200字符长度
 */
function getExcerpt($content, $length = 200) {
    // 如果内容长度不超过限制，直接返回原内容
    if (mb_strlen($content, 'UTF-8') <= $length) {
        return $content;
    }
    // 使用mb_substr支持中文字符截取，并添加省略号
    return mb_substr($content, 0, $length, 'UTF-8') . '...';
}

/**
 * 获取文章默认图标函数
 * 
 * 这个函数为没有配图的文章生成默认图标
 * 根据文章ID生成不同的emoji图标，让页面更有趣
 * 
 * @param int $articleId 文章ID
 * @return string 对应的emoji图标字符
 * 
 * 使用示例：
 * echo getArticleImage($article['id']); // 显示文章对应的emoji图标
 * <div class="article-icon"><?php echo getArticleImage(1); ?></div>
 */
function getArticleImage($articleId) {
    // 定义一组emoji图标
    $icons = ['📝', '✨', '🎯', '💡', '🌟', '🔥', '💎', '🎨', '🚀', '⭐', '🎪', '🌈'];
    // 根据文章ID取模运算，确保每篇文章都有固定的图标
    return $icons[$articleId % count($icons)];
}
?> 